package com.hoshiicloud.vericenter.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hoshiicloud.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Marker
 * @date 2019/2/17-13:03
 * @email markerccc@163.com
 */
@Slf4j
public class ALiYunUtil {

    private static final String FALSE_CRITERIA = "1";
    private static final String TRUE_CRITERIA = "0";
    //private static final String ALIYUN_CODE = "3fb08054b979418cac4c9263503f1091";
    private static final String ALIYUN_CODE = "206cf9d8e3bd45fbb6459ae3920dba89";

    public static List getExpressMessage(String expNo,String expType){
        String host = "https://wuliu.market.alicloudapi.com";
        String path = "/kdi";
        String method = "GET";
        Map<String, String> headers = new HashMap<String, String>();
        String appCode="3fb08054b979418cac4c9263503f1091";
        headers.put("Authorization", "APPCODE " + appCode); //格式为:Authorization:APPCODE 3fb08054b979418cac4c9263503f1091;
        Map<String,String> query=new HashMap<String,String>();
        query.put("no",expNo);
        query.put("type",expType);
        try {
            HttpResponse response = HttpUtils.doGet(host, path, method, headers, query);
            String rs = EntityUtils.toString(response.getEntity());
            JSONObject object = JSONObject.parseObject(rs);
            if (!object.get("status").toString().equals("0")) {
                throw new ServiceException(object.get("msg").toString());
            }
            Map<String, List<Map<String, String>>> maprs = object.getObject("result", Map.class);
            return maprs.get("list");
        } catch (Exception e) {
            throw new ServiceException("获取物流信息异常,请稍后重试");
        }
    }

    /**
     * @param realName 真实姓名
     * @param idNo 身份证号码
     * @param cardNo 银行卡号
     * @return java.util.Map<java.lang.String,java.lang.Object>
     * @author: Mr.wu
     * @descripton: 银行卡三要素验证接口，如处理失败抛出异常到全局异常捕获类处理
     * @date: 10:35 2019/5/28
     */
    public static Map<String, Object> getBankCardThreeElementVerificationMessage(String realName, String idNo, String cardNo) {
        String host = "https://ali-bankcard4.showapi.com";
        String path = "/bank3";
        String method = "GET";
        String appcode = ALIYUN_CODE;
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("acct_name", realName);
        querys.put("acct_pan", cardNo);
        querys.put("cert_id", idNo);
        querys.put("cert_type", "01");
        querys.put("needBelongArea", "true");

        HashMap<String, Object> returnMap = null;
        returnMap = sendRequest(host, path, method, headers, querys, "");
        log.info("接口返回:"+returnMap.toString());
        verifyBankCardThreeElement(returnMap);


        return returnMap;
    }

    /**
     * 营业执照信息验证
     *
     * @param file 图片文件
     * @return returnMap 验证成功后返回的信息
     */
    public static Map<String, Object> getBusinessLicenseMessage(MultipartFile file) {
        String encode = null;
        try {
            encode = Base64.getEncoder().encodeToString(file.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

        String host = "https://dm-58.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_business_license.json";
        String method = "POST";

        Map<String, String> headers = setHeaders();
        Map<String, String> querys = new HashMap<>(15);

        String bodys = "{\"image\":\"" + encode + "\"}";
        HashMap<String, Object> returnMap = null;
        returnMap = sendRequest(host, path, method, headers, querys, bodys);

        int returnMapSize = 18;

        if (returnMap.size() != returnMapSize) {
            throw new ServiceException("请上传正确的营业执照");
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String establishDateStr = (String) returnMap.getOrDefault("establish_date", "");
        String validPeriodStr = (String) returnMap.getOrDefault("valid_period", "");
        if (StringUtils.isBlank(establishDateStr) || StringUtils.isBlank(validPeriodStr)) {
            throw new ServiceException("请上传正确的营业执照");
        }

        Date startDate = null;
        Date validPeriod = null;
        String startDateFormat = null;
        String validPeriodFormat = null;
        try {
            startDate = simpleDateFormat.parse(establishDateStr);
        } catch (ParseException e) {
            startDateFormat = "日期识别失败, 手动填写";
        }
        try {
            validPeriod = simpleDateFormat.parse(validPeriodStr);
        } catch (ParseException e) {
            validPeriodFormat = "日期识别失败, 手动填写";
        }
        if (null == startDateFormat) {
            startDateFormat = dateFormat.format(startDate);
        }
        returnMap.put("establishDate", startDateFormat);

        if (null == validPeriodFormat) {
            validPeriodFormat = dateFormat.format(validPeriod);
        }
        returnMap.put("validPeriod", validPeriodFormat);

        return returnMap;

    }


    /**
     * 身份证OCR验证
     *
     * @param image      图片url或图片base64字符串
     * @param side 身份证正反面 face或back
     * @return returnMap 验证返回的身份证参数
     */
    public static Map<String, Object> getIdCardVerificationMessage(String image,
                                                                   String side) {
        String host = "http://dm-51.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_idcard.json";
        String method = "POST";
        //请根据线上文档修改configure字段
        JSONObject configObj = new JSONObject();

        configObj.put("side", side);

        String configStr = configObj.toString();
        JSONObject requestObj = new JSONObject();
        requestObj.put("image", image);
        if (configStr.length() > 0) {
            requestObj.put("configure", configStr);
        }

        String bodys = requestObj.toString();

        Map<String, String> headers = setHeaders();
        Map<String, String> querys = new HashMap<>(15);
        HashMap<String, Object> returnMap = null;
        returnMap = sendRequest(host, path, method, headers, querys, bodys);

        String backCriteria = "1";
        if ("back".equals(side)) {
            //进行时间格式化
            SimpleDateFormat idCardDateFormat = new SimpleDateFormat("yyyyMMdd");
            Date startDate = null;
            Date endDate = null;
            try {
                startDate = idCardDateFormat
                        .parse(returnMap.get("start_date").toString());
                endDate = idCardDateFormat
                        .parse(returnMap.get("end_date").toString());
            } catch (ParseException e) {
                log.error("==============================> 日期转换失败");
            }
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String startDateStr = dateFormat.format(startDate);
            String endDateStr = dateFormat.format(endDate);
            returnMap.put("start_date", startDateStr);
            returnMap.put("end_date", endDateStr);
            return returnMap;
        }
        //返回值
        return returnMap;
    }

    /**
     * 身份证实名认证最新版
     *
     * @param cardNo   身份证号码
     * @param realName 姓名
     * @return 反馈信息
     */
    public static Map<String, Object> getPersonVerificationMessage(String realName, String cardNo) {
        String host = "https://1.api.apistore.cn";
        String path = "/idcard3";
        String method = "POST";
        Map<String, String> headers = new HashMap<>(16);
        headers.put("Authorization", "APPCODE " + ALIYUN_CODE);
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<>(16);
        Map<String, String> bodys = new HashMap<>(16);
        bodys.put("cardNo", cardNo);
        bodys.put("realName", realName);
        Map<String, Object> returnMap = null;
        returnMap = sendRequest(host, path, method, headers, querys, bodys);
        log.info("接口返回:"+returnMap.toString());
        String errorCode = returnMap.get("error_code").toString();
        verificationCode(errorCode);
        return returnMap;
    }

    private static void verificationCode(String errorCode) {
        // 0	认证通过	信息一致
        // 80001	参数不完整	参数不完整
        // 80003	姓名格式不正确	姓名格式不正确
        // 80004	身份证号码格式不正确	身份证号码格式不正确
        // 80008	身份证中心维护，请稍后重试	身份证中心维护，请稍后重试
        // 90033	无此身份证号码	无此身份证号码
        // 90099	认证不通过	信息不一致
        if ("0".equals(errorCode)) {
            log.info("实名认证验证成功");
        }

        if ("80001".equals(errorCode)) {
            throw new ServiceException("参数不完整");
        }

        if ("80003".equals(errorCode)) {
            throw new ServiceException("姓名格式不正确, 请上传更加清晰的身份证图片");
        }

        if ("80004".equals(errorCode)) {
            throw new ServiceException("身份证号码格式不正确, 请上传更加清晰的身份证图片");
        }

        if ("80008".equals(errorCode)) {
            throw new ServiceException("身份证中心维护，请稍后重试");
        }

        if ("90033".equals(errorCode)) {
            throw new ServiceException("无此身份证号码");
        }
        if ("90099".equals(errorCode)) {
            throw new ServiceException("身份证信息不一致");
        }
    }

    /**
     * 设置头信息
     *
     * @return Map
     */
    private static Map<String, String> setHeaders() {
        Map<String, String> headers = new HashMap<>(15);
        headers.put("Authorization", "APPCODE " + ALIYUN_CODE);
        headers.put("Content-Type", "application/json; charset=UTF-8");
        return headers;
    }

    /**
     * 验证公司信息
     *
     * @param companyName 公司名称
     * @return Map
     */
    public static Map<String, Object> getCompanyMessage(String companyName) {
        String host = "http://cdetail.market.alicloudapi.com";
        String path = "/lianzhuo/cdetails";
        String method = "GET";
        // 这里是不需要的, 只是为了对应接口
        String bodys = "";
        Map<String, String> headers = new HashMap<>(16);
        headers.put("Authorization", "APPCODE " + ALIYUN_CODE);
        Map<String, String> querys = new HashMap<>(16);
        querys.put("keyword", companyName);
        HashMap<String, Object> returnMap = null;
        returnMap = sendRequest(host, path, method, headers, querys,
                bodys);
        return returnMap;
    }

    /**
     * 捕获阿里云的异常
     *
     * @param response 响应体
     */
    private static void catchALiYunExceptions(HttpResponse response) {
        Integer statusCode = response.getStatusLine().getStatusCode();
        // 抛出异常信息
        verifyCode(response, statusCode);
    }

    /**
     * 验证银行卡三要素校验的返回码,不为成功时抛出异常
     *
     * @param result 接口响应内容
     */
    private static void verifyBankCardThreeElement(Map<String, Object> result) {
        if (!result.get("showapi_res_code").toString().equals("0")) {
            throw new ServiceException(result.get("showapi_res_error").toString());
        }
        JSONObject jsonObject = JSON.parseObject(result.get("showapi_res_body").toString());
        if (!jsonObject.getString("code").equals("0")) {
            throw new ServiceException(jsonObject.getString("msg"));
        }
    }

    /**
     * 验证获取物流信息接口的返回码,不为成功时抛出异常
     *
     * @param result 接口响应内容
     */
    private static void verifyExpressMessage(Map<String, Object> result) {
        if (!result.get("status").toString().equals("0")) {
            throw new ServiceException(result.get("msg").toString());
        }
    }

    /**
     * 验证Code
     *
     * @param response   响应
     * @param statusCode 状态代码
     */
    private static void verifyCode(HttpResponse response, Integer statusCode) {
        /*
         * accessModeCode: 访问方式错误
         * paramNotValidCode: 请求参数不合法
         * appkeyNumCode: appkey验证错误或服务请求次数为0
         * appkeyIsNullCode: appkey不能为空
         * systemErrorCode: 系统服务错误
         * systemNullCode: 系统无记录
         * messageNullCode: 无效信息记录
         * */
        Integer accessModeCode = 400;
        Integer paramNotValidCode = 401;
        Integer appkeyNumCode = 402;
        Integer appkeyIsNullCode = 403;
        Integer systemErrorCode = 500;
        Integer systemNullCode = 501;
        Integer messageNullCode = 464;

        if (statusCode.equals(accessModeCode)) {
            log.error("----------------------> errorStr: 访问方式错误, Http code:{}, \n response: {}",
                    statusCode, response);
        }

        if (statusCode.equals(paramNotValidCode)) {
            log.error("----------------------> errorStr: 请求参数不合法, Http code:{}, \n response: {}",
                    statusCode, response);
        }

        if (statusCode.equals(appkeyNumCode)) {
            log.error("----------------------> errorStr: appkey验证错误或服务请求次数为0, Http code:{}, \n response: {}",
                    statusCode, response);
        }

        if (statusCode.equals(appkeyIsNullCode)) {
            log.error("----------------------> errorStr: appkey不能为空, Http code:{}, \n response: {}",
                    statusCode, response);
        }

        if (statusCode.equals(systemErrorCode)) {
            log.error("----------------------> errorStr: 系统服务错误, Http code:{}, \n response: {}",
                    statusCode, response);
            throw new ServiceException("系统服务错误, 稍后重试");
        }

        if (statusCode.equals(systemNullCode)) {
            log.error("----------------------> errorStr: 系统无记录, Http code:{}, \n response: {}",
                    statusCode, response);
            throw new ServiceException("无法识别营业执照/身份证上的信息, 请上传清晰的营业执照/身份证照片之后确认信息");
        }
        if (statusCode.equals(messageNullCode)) {
            log.error("----------------------> errorStr: 系统无记录, Http code:{}, \n response: {}",
                    statusCode, response);
            throw new ServiceException("无法识别营业执照/身份证上的信息, 请上传清晰的营业执照/身份证照片之后确认信息");
        }
    }

    /**
     * 发送请求
     *
     * @param host    路径
     * @param path    路径
     * @param method  方法
     * @param headers 请求头
     * @param querys  查询体
     * @param bodys   body
     * @return HashMap
     */
    private static HashMap<String, Object> sendRequest(String host, String path,
                                                       String method, Map<String, String> headers, Map<String, String> querys, String bodys) {
        HttpResponse response = null;
        String post = "POST";
        String get = "GET";
        if (StringUtils.isNotBlank(method) && post.equals(method)) {
            // POST请求
            try {
                response = HttpUtils
                        .doPost(host, path, method, headers, querys, bodys);
            } catch (Exception e) {
                log.error("---------------------->\n error: Post请求调用错误");
                throw new ServiceException("上传失败, 请重试, 多次失败请联系管理人员");
            }

        }
        if (StringUtils.isNotBlank(method) && get.equals(method)) {
            // GET请求
            try {
                response = HttpUtils
                        .doGet(host, path, method, headers, querys);
            } catch (Exception e) {
                log.error("---------------------->\n error: Get请求调用错误");
                throw new ServiceException("上传失败, 请重试, 多次失败请联系管理人员");
            }
        }
        catchALiYunExceptions(response);
        String message = null;
        try {
            message = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            log.error("-->{e}");
        }
        if ("Invalid Input - wrong category".equals(message)) {
            throw new ServiceException("请上传正确方向的身份证照");
        }
        return JSONObject.parseObject(message, HashMap.class);
    }

    /**
     * 处理为bodys为Map的请求
     *
     * @param host    路径
     * @param path    接口地址
     * @param method  请求方法
     * @param headers 请求头
     * @param querys  查询体
     * @param bodys   参数
     * @return Map
     */
    private static HashMap<String, Object> sendRequest(String host, String path,
                                                       String method, Map<String, String> headers, Map<String, String> querys,
                                                       Map<String, String> bodys) {
        HttpResponse response = null;
        String post = "POST";
        String get = "GET";
        if (StringUtils.isNotBlank(method) && post.equals(method)) {
            // POST请求
            if (StringUtils.isBlank(bodys.get("cardNo"))) {
                throw new ServiceException("身份证号码不能为空");
            }

            if (StringUtils.isBlank(bodys.get("realName"))) {
                throw new ServiceException("姓名不能为空");
            }

            try {
                response = HttpUtils
                        .doPost(host, path, method, headers, querys, bodys);
            } catch (Exception e) {
                log.error("=======================================>\n error: Post请求调用错误");
                throw new ServiceException("上传失败, 请重试, 多次失败请联系管理人员");
            }
        }
        if (StringUtils.isNotBlank(method) && get.equals(method)) {
            // GET请求
            try {
                response = HttpUtils
                        .doGet(host, path, method, headers, querys);
            } catch (Exception e) {
                log.error("=======================================>\n error: Get请求调用错误");
                throw new ServiceException("上传失败, 请重试, 多次失败请联系管理人员");
            }
        }
        // 断定response不为null
        assert response != null;
        catchALiYunExceptions(response);
        String message = null;
        try {
            message = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            log.error("-->{0}", e);
        }
        return JSONObject.parseObject(message, HashMap.class);
    }

}




